{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "81c9fa77",
   "metadata": {},
   "source": [
    "## 并行节点执行\n",
    "\n",
    "在模块3中，我们深入探讨了人类控制，展示了3个常见用例：<br/>\n",
    "\n",
    "(1) 批准 - 我们可以中断Agent，向用户显示状态，并允许用户接受操作。<br/>\n",
    "(2) 调试 - 我们可以倒回图以重现或避免问题。<br/>\n",
    "(3) 编辑 - 可以修改状态。<br/>\n",
    "\n",
    "\n",
    "### 目标\n",
    "我们将在本模块中深入研究“多代理”工作流程<br/>\n",
    "要构建多代理，我们将首先讨论一些LangGraph可控性主题。<br/>\n",
    "\n",
    "我们将从并行化开始 <br/>\n",
    "\n",
    "## 输入和输出\n",
    "让我们构建一个简单的线性图，在每个步骤中覆盖状态<br/>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "6afab397",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%capture --no-stderr\n",
    "%pip install -U wikipedia"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "a0fa09b8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "OPENAI_API_KEY: ········\n",
      "OPENAI_BASE_URL: ········\n"
     ]
    }
   ],
   "source": [
    "import os, getpass\n",
    "\n",
    "def _set_env(var: str):\n",
    "    if not os.environ.get(var):\n",
    "        os.environ[var] = getpass.getpass(f\"{var}: \")\n",
    "\n",
    "_set_env(\"OPENAI_API_KEY\")\n",
    "_set_env(\"OPENAI_BASE_URL\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "456e0712",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Package                  Version\n",
      "------------------------ -----------\n",
      "aiohappyeyeballs         2.6.1\n",
      "aiohttp                  3.11.18\n",
      "aiosignal                1.3.2\n",
      "annotated-types          0.6.0\n",
      "anyio                    4.6.2\n",
      "asttokens                3.0.0\n",
      "async-timeout            4.0.3\n",
      "attrs                    25.3.0\n",
      "beautifulsoup4           4.13.4\n",
      "Brotli                   1.0.9\n",
      "certifi                  2025.1.31\n",
      "charset-normalizer       3.3.2\n",
      "colorama                 0.4.6\n",
      "comm                     0.2.1\n",
      "dataclasses-json         0.6.7\n",
      "debugpy                  1.8.11\n",
      "decorator                5.1.1\n",
      "distro                   1.9.0\n",
      "exceptiongroup           1.2.0\n",
      "executing                0.8.3\n",
      "frozenlist               1.6.0\n",
      "greenlet                 3.2.0\n",
      "h11                      0.14.0\n",
      "httpcore                 1.0.2\n",
      "httpx                    0.27.0\n",
      "httpx-sse                0.4.0\n",
      "idna                     3.7\n",
      "ipykernel                6.29.5\n",
      "ipython                  8.30.0\n",
      "jedi                     0.19.2\n",
      "jiter                    0.6.1\n",
      "jsonpatch                1.33\n",
      "jsonpointer              3.0.0\n",
      "jupyter_client           8.6.3\n",
      "jupyter_core             5.7.2\n",
      "langchain                0.3.23\n",
      "langchain-community      0.3.21\n",
      "langchain-core           0.3.54\n",
      "langchain-openai         0.3.14\n",
      "langchain-text-splitters 0.3.8\n",
      "langgraph                0.3.33\n",
      "langgraph-checkpoint     2.0.24\n",
      "langgraph-prebuilt       0.1.8\n",
      "langgraph-sdk            0.1.63\n",
      "langsmith                0.3.32\n",
      "marshmallow              3.26.1\n",
      "matplotlib-inline        0.1.6\n",
      "multidict                6.4.3\n",
      "mypy-extensions          1.0.0\n",
      "nest-asyncio             1.6.0\n",
      "numpy                    2.2.5\n",
      "openai                   1.75.0\n",
      "orjson                   3.10.16\n",
      "ormsgpack                1.9.1\n",
      "packaging                24.2\n",
      "parso                    0.8.4\n",
      "pip                      25.0\n",
      "platformdirs             4.3.7\n",
      "prompt-toolkit           3.0.43\n",
      "propcache                0.3.1\n",
      "psutil                   5.9.0\n",
      "pure-eval                0.2.2\n",
      "pydantic                 2.10.3\n",
      "pydantic_core            2.27.1\n",
      "pydantic-settings        2.9.1\n",
      "Pygments                 2.19.1\n",
      "PySocks                  1.7.1\n",
      "python-dateutil          2.9.0.post0\n",
      "python-dotenv            1.1.0\n",
      "pywin32                  308\n",
      "PyYAML                   6.0.2\n",
      "pyzmq                    26.2.0\n",
      "regex                    2024.11.6\n",
      "requests                 2.32.3\n",
      "requests-toolbelt        1.0.0\n",
      "setuptools               75.8.0\n",
      "six                      1.17.0\n",
      "sniffio                  1.3.0\n",
      "soupsieve                2.7\n",
      "SQLAlchemy               2.0.40\n",
      "stack-data               0.2.0\n",
      "tavily-python            0.5.4\n",
      "tenacity                 9.1.2\n",
      "tiktoken                 0.9.0\n",
      "tornado                  6.4.2\n",
      "tqdm                     4.67.1\n",
      "traitlets                5.14.3\n",
      "typing_extensions        4.12.2\n",
      "typing-inspect           0.9.0\n",
      "typing-inspection        0.4.0\n",
      "urllib3                  2.3.0\n",
      "wcwidth                  0.2.5\n",
      "wheel                    0.45.1\n",
      "wikipedia                1.4.0\n",
      "win-inet-pton            1.1.0\n",
      "xxhash                   3.5.0\n",
      "yarl                     1.20.0\n",
      "zstandard                0.23.0\n",
      "Note: you may need to restart the kernel to use updated packages.\n"
     ]
    }
   ],
   "source": [
    "pip list"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "41a1a71c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import Image, display\n",
    "\n",
    "from typing import Any\n",
    "from typing_extensions import TypedDict\n",
    "\n",
    "from langgraph.graph import StateGraph, START, END\n",
    "\n",
    "class State(TypedDict):\n",
    "    state: str\n",
    "\n",
    "class ReturnNodeValue:\n",
    "    def __init__(self, node_secret: str):\n",
    "        self._value = node_secret\n",
    "\n",
    "    def __call__(self, state: State) -> Any:\n",
    "        print(f\"增加 {self._value} to {state['state']}\")\n",
    "        return {\"state\": [self._value]}\n",
    "\n",
    "# 添加节点\n",
    "builder = StateGraph(State)\n",
    "\n",
    "# 使用 node_secret 初始化每个节点\n",
    "builder.add_node(\"a\", ReturnNodeValue(\"我是 A\"))\n",
    "builder.add_node(\"b\", ReturnNodeValue(\"我是 B\"))\n",
    "builder.add_node(\"c\", ReturnNodeValue(\"我是 C\"))\n",
    "builder.add_node(\"d\", ReturnNodeValue(\"我是 D\"))\n",
    "\n",
    "# 流程\n",
    "builder.add_edge(START, \"a\")\n",
    "builder.add_edge(\"a\", \"b\")\n",
    "builder.add_edge(\"b\", \"c\")\n",
    "builder.add_edge(\"c\", \"d\")\n",
    "builder.add_edge(\"d\", END)\n",
    "graph = builder.compile()\n",
    "\n",
    "display(Image(graph.get_graph().draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "68c07242",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "增加 我是 A to []\n",
      "增加 我是 B to ['我是 A']\n",
      "增加 我是 C to ['我是 B']\n",
      "增加 我是 D to ['我是 C']\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'state': ['我是 D']}"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "graph.invoke({\"state\": []})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "6153a6ca",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "builder = StateGraph(State)\n",
    "\n",
    "\n",
    "builder.add_node(\"a\", ReturnNodeValue(\"我是 A\"))\n",
    "builder.add_node(\"b\", ReturnNodeValue(\"我是 B\"))\n",
    "builder.add_node(\"c\", ReturnNodeValue(\"我是 C\"))\n",
    "builder.add_node(\"d\", ReturnNodeValue(\"我是 D\"))\n",
    "\n",
    "builder.add_edge(START, \"a\")\n",
    "builder.add_edge(\"a\", \"b\")\n",
    "builder.add_edge(\"a\", \"c\")\n",
    "builder.add_edge(\"b\", \"d\")\n",
    "builder.add_edge(\"c\", \"d\")\n",
    "builder.add_edge(\"d\", END)\n",
    "graph = builder.compile()\n",
    "\n",
    "display(Image(graph.get_graph().draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "0cbafa61",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "增加 我是 A to []\n",
      "增加 我是 B to ['我是 A']\n",
      "增加 我是 C to ['我是 A']\n",
      "发生一个错误: At key 'state': Can receive only one value per step. Use an Annotated key to handle multiple values.\n",
      "For troubleshooting, visit: https://python.langchain.com/docs/troubleshooting/errors/INVALID_CONCURRENT_GRAPH_UPDATE\n"
     ]
    }
   ],
   "source": [
    "from langgraph.errors import InvalidUpdateError\n",
    "try:\n",
    "    graph.invoke({\"state\": []})\n",
    "except InvalidUpdateError as e:\n",
    "    print(f\"发生一个错误: {e}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "ab0cf68f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import operator\n",
    "from typing import Annotated\n",
    "\n",
    "class State(TypedDict):\n",
    "    # operator.add Reducer fn 使其成为仅附加的\n",
    "    state: Annotated[list, operator.add]\n",
    "\n",
    "# 增加节点\n",
    "builder = StateGraph(State)\n",
    "\n",
    "builder.add_node(\"a\", ReturnNodeValue(\"我是 A\"))\n",
    "builder.add_node(\"b\", ReturnNodeValue(\"我是 B\"))\n",
    "builder.add_node(\"c\", ReturnNodeValue(\"我是 C\"))\n",
    "builder.add_node(\"d\", ReturnNodeValue(\"我是 D\"))\n",
    "\n",
    "builder.add_edge(START, \"a\")\n",
    "builder.add_edge(\"a\", \"b\")\n",
    "builder.add_edge(\"a\", \"c\")\n",
    "builder.add_edge(\"b\", \"d\")\n",
    "builder.add_edge(\"c\", \"d\")\n",
    "builder.add_edge(\"d\", END)\n",
    "graph = builder.compile()\n",
    "\n",
    "display(Image(graph.get_graph().draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "06aecec6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "增加 我是 A to []\n",
      "增加 我是 B to ['我是 A']\n",
      "增加 我是 C to ['我是 A']\n",
      "增加 我是 D to ['我是 A', '我是 B', '我是 C']\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'state': ['我是 A', '我是 B', '我是 C', '我是 D']}"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "graph.invoke({\"state\": []})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "f6a5542a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "builder = StateGraph(State)\n",
    "\n",
    "builder.add_node(\"a\", ReturnNodeValue(\"我是 A\"))\n",
    "builder.add_node(\"b\", ReturnNodeValue(\"我是 B\"))\n",
    "builder.add_node(\"b2\", ReturnNodeValue(\"我是 B2\"))\n",
    "builder.add_node(\"c\", ReturnNodeValue(\"我是 C\"))\n",
    "builder.add_node(\"d\", ReturnNodeValue(\"我是 D\"))\n",
    "\n",
    "builder.add_edge(START, \"a\")\n",
    "builder.add_edge(\"a\", \"b\")\n",
    "builder.add_edge(\"a\", \"c\")\n",
    "builder.add_edge(\"b\", \"b2\")\n",
    "builder.add_edge([\"b2\", \"c\"], \"d\")\n",
    "builder.add_edge(\"d\", END)\n",
    "graph = builder.compile()\n",
    "\n",
    "display(Image(graph.get_graph().draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "1f3edf65",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "增加 我是 A to []\n",
      "增加 我是 B to ['我是 A']\n",
      "增加 我是 C to ['我是 A']\n",
      "增加 我是 D to ['我是 A', '我是 B', '我是 C']\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'state': ['我是 A', '我是 B', '我是 C', '我是 D']}"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "graph.invoke({\"state\": []})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "1980efbb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def sorting_reducer(left, right):\n",
    "    \"\"\" 组合并排序列表中的值\"\"\"\n",
    "    if not isinstance(left, list):\n",
    "        left = [left]\n",
    "\n",
    "    if not isinstance(right, list):\n",
    "        right = [right]\n",
    "    \n",
    "    return sorted(left + right, reverse=False)\n",
    "\n",
    "class State(TypedDict):\n",
    "    # sorting_reducer 将对状态中的值进行排序\n",
    "    state: Annotated[list, sorting_reducer]\n",
    "\n",
    "builder = StateGraph(State)\n",
    "\n",
    "builder.add_node(\"a\", ReturnNodeValue(\"我是 A\"))\n",
    "builder.add_node(\"b\", ReturnNodeValue(\"我是 B\"))\n",
    "builder.add_node(\"b2\", ReturnNodeValue(\"我是 B2\"))\n",
    "builder.add_node(\"c\", ReturnNodeValue(\"我是 C\"))\n",
    "builder.add_node(\"d\", ReturnNodeValue(\"我是 D\"))\n",
    "\n",
    "builder.add_edge(START, \"a\")\n",
    "builder.add_edge(\"a\", \"b\")\n",
    "builder.add_edge(\"a\", \"c\")\n",
    "builder.add_edge(\"b\", \"b2\")\n",
    "builder.add_edge([\"b2\", \"c\"], \"d\")\n",
    "builder.add_edge(\"d\", END)\n",
    "graph = builder.compile()\n",
    "\n",
    "display(Image(graph.get_graph().draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "c4c19f74",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "增加 我是 A to []\n",
      "增加 我是 B to ['我是 A']\n",
      "增加 我是 C to ['我是 A']\n",
      "增加 我是 B2 to ['我是 A', '我是 B', '我是 C']\n",
      "增加 我是 D to ['我是 A', '我是 B', '我是 B2', '我是 C']\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'state': ['我是 A', '我是 B', '我是 B2', '我是 C', '我是 D']}"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "graph.invoke({\"state\": []})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "db8f739e",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "llm = ChatOpenAI(model=\"gpt-4o\", temperature=0) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "4d7046c7",
   "metadata": {},
   "outputs": [],
   "source": [
    "class State(TypedDict):\n",
    "    question: str\n",
    "    answer: str\n",
    "    context: Annotated[list, operator.add]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "3e305ba0",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os, getpass\n",
    "def _set_env(var: str):\n",
    "    if not os.environ.get(var):\n",
    "        os.environ[var] = getpass.getpass(f\"{var}: \")\n",
    "_set_env(\"TAVILY_API_KEY\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "168790b7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "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\n"
     ]
    }
   ],
   "source": [
    "print(os.environ[\"TAVILY_API_KEY\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "01aeceef",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from langchain_core.messages import HumanMessage, SystemMessage\n",
    "\n",
    "from langchain_community.document_loaders import WikipediaLoader\n",
    "from langchain_community.tools import TavilySearchResults\n",
    "\n",
    "def search_web(state):\n",
    "    \n",
    "    \"\"\" 从网络搜索中检索文档 \"\"\"\n",
    "\n",
    "    # 搜索\n",
    "    tavily_search = TavilySearchResults(max_results=3)\n",
    "    search_docs = tavily_search.invoke(state['question'])\n",
    "\n",
    "    # 格式化搜索到的信息\n",
    "    formatted_search_docs = \"\\n\\n---\\n\\n\".join(\n",
    "        [\n",
    "            f'<Document href=\"{doc[\"url\"]}\">\\n{doc[\"content\"]}\\n</Document>'\n",
    "            for doc in search_docs\n",
    "        ]\n",
    "    )\n",
    "\n",
    "    return {\"context\": [formatted_search_docs]} \n",
    "\n",
    "def search_wikipedia(state):\n",
    "    \n",
    "    \"\"\" 从维基百科检索文档 \"\"\"\n",
    "\n",
    "    # 搜索\n",
    "    search_docs = WikipediaLoader(query=state['question'], \n",
    "                                  load_max_docs=2).load()\n",
    "\n",
    "     # 格式化搜索到的信息\n",
    "    formatted_search_docs = \"\\n\\n---\\n\\n\".join(\n",
    "        [\n",
    "            f'<Document source=\"{doc.metadata[\"source\"]}\" page=\"{doc.metadata.get(\"page\", \"\")}\">\\n{doc.page_content}\\n</Document>'\n",
    "            for doc in search_docs\n",
    "        ]\n",
    "    )\n",
    "\n",
    "    return {\"context\": [formatted_search_docs]} \n",
    "\n",
    "def generate_answer(state):\n",
    "    \n",
    "    \"\"\" 回答问题的节点 \"\"\"\n",
    "\n",
    "    # 获取状态\n",
    "    context = state[\"context\"]\n",
    "    question = state[\"question\"]\n",
    "\n",
    "    # 模板\n",
    "    answer_template = \"\"\"使用以下上下文回答问题 {question} : {context}\"\"\"\n",
    "    answer_instructions = answer_template.format(question=question, \n",
    "                                                       context=context)    \n",
    "    \n",
    "    # 回答\n",
    "    answer = llm.invoke([SystemMessage(content=answer_instructions)]+[HumanMessage(content=f\"回答这个问题。\")])\n",
    "      \n",
    "    # 将其附加到状态\n",
    "    return {\"answer\": answer}\n",
    "\n",
    "# 添加节点\n",
    "builder = StateGraph(State)\n",
    "\n",
    "# 使用节点密钥初始化每个节点\n",
    "builder.add_node(\"search_web\",search_web)\n",
    "builder.add_node(\"search_wikipedia\", search_wikipedia)\n",
    "builder.add_node(\"generate_answer\", generate_answer)\n",
    "\n",
    "# 流程\n",
    "builder.add_edge(START, \"search_wikipedia\")\n",
    "builder.add_edge(START, \"search_web\")\n",
    "builder.add_edge(\"search_wikipedia\", \"generate_answer\")\n",
    "builder.add_edge(\"search_web\", \"generate_answer\")\n",
    "builder.add_edge(\"generate_answer\", END)\n",
    "graph = builder.compile()\n",
    "\n",
    "display(Image(graph.get_graph().draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "b8c6f607",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "ename": "ConnectTimeout",
     "evalue": "HTTPConnectionPool(host='en.wikipedia.org', port=80): Max retries exceeded with url: /w/api.php?list=search&srprop=&srlimit=2&limit=2&srsearch=%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B42024%E5%B9%B4%E7%9A%84%E8%90%A5%E4%B8%9A%E6%94%B6%E5%85%A5%E6%98%AF%E5%A4%9A%E5%B0%91%EF%BC%9F%E5%92%8C2023%E5%B9%B4%E7%9B%B8%E6%AF%94%E6%80%8E%E4%B9%88%E6%A0%B7%EF%BC%9F&format=json&action=query (Caused by ConnectTimeoutError(<urllib3.connection.HTTPConnection object at 0x000002BE183C6C20>, 'Connection to en.wikipedia.org timed out. (connect timeout=None)'))",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTimeoutError\u001b[0m                              Traceback (most recent call last)",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\urllib3\\connection.py:198\u001b[0m, in \u001b[0;36mHTTPConnection._new_conn\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m    197\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m--> 198\u001b[0m     sock \u001b[38;5;241m=\u001b[39m \u001b[43mconnection\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcreate_connection\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m    199\u001b[0m \u001b[43m        \u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_dns_host\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mport\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    200\u001b[0m \u001b[43m        \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtimeout\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    201\u001b[0m \u001b[43m        \u001b[49m\u001b[43msource_address\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msource_address\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    202\u001b[0m \u001b[43m        \u001b[49m\u001b[43msocket_options\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msocket_options\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    203\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m    204\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m socket\u001b[38;5;241m.\u001b[39mgaierror \u001b[38;5;28;01mas\u001b[39;00m e:\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\urllib3\\util\\connection.py:85\u001b[0m, in \u001b[0;36mcreate_connection\u001b[1;34m(address, timeout, source_address, socket_options)\u001b[0m\n\u001b[0;32m     84\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m---> 85\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m err\n\u001b[0;32m     86\u001b[0m \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[0;32m     87\u001b[0m     \u001b[38;5;66;03m# Break explicitly a reference cycle\u001b[39;00m\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\urllib3\\util\\connection.py:73\u001b[0m, in \u001b[0;36mcreate_connection\u001b[1;34m(address, timeout, source_address, socket_options)\u001b[0m\n\u001b[0;32m     72\u001b[0m     sock\u001b[38;5;241m.\u001b[39mbind(source_address)\n\u001b[1;32m---> 73\u001b[0m \u001b[43msock\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconnect\u001b[49m\u001b[43m(\u001b[49m\u001b[43msa\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m     74\u001b[0m \u001b[38;5;66;03m# Break explicitly a reference cycle\u001b[39;00m\n",
      "\u001b[1;31mTimeoutError\u001b[0m: [WinError 10060] 由于连接方在一段时间后没有正确答复或连接的主机没有反应，连接尝试失败。",
      "\nThe above exception was the direct cause of the following exception:\n",
      "\u001b[1;31mConnectTimeoutError\u001b[0m                       Traceback (most recent call last)",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\urllib3\\connectionpool.py:787\u001b[0m, in \u001b[0;36mHTTPConnectionPool.urlopen\u001b[1;34m(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)\u001b[0m\n\u001b[0;32m    786\u001b[0m \u001b[38;5;66;03m# Make the request on the HTTPConnection object\u001b[39;00m\n\u001b[1;32m--> 787\u001b[0m response \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_make_request(\n\u001b[0;32m    788\u001b[0m     conn,\n\u001b[0;32m    789\u001b[0m     method,\n\u001b[0;32m    790\u001b[0m     url,\n\u001b[0;32m    791\u001b[0m     timeout\u001b[38;5;241m=\u001b[39mtimeout_obj,\n\u001b[0;32m    792\u001b[0m     body\u001b[38;5;241m=\u001b[39mbody,\n\u001b[0;32m    793\u001b[0m     headers\u001b[38;5;241m=\u001b[39mheaders,\n\u001b[0;32m    794\u001b[0m     chunked\u001b[38;5;241m=\u001b[39mchunked,\n\u001b[0;32m    795\u001b[0m     retries\u001b[38;5;241m=\u001b[39mretries,\n\u001b[0;32m    796\u001b[0m     response_conn\u001b[38;5;241m=\u001b[39mresponse_conn,\n\u001b[0;32m    797\u001b[0m     preload_content\u001b[38;5;241m=\u001b[39mpreload_content,\n\u001b[0;32m    798\u001b[0m     decode_content\u001b[38;5;241m=\u001b[39mdecode_content,\n\u001b[0;32m    799\u001b[0m     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mresponse_kw,\n\u001b[0;32m    800\u001b[0m )\n\u001b[0;32m    802\u001b[0m \u001b[38;5;66;03m# Everything went great!\u001b[39;00m\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\urllib3\\connectionpool.py:493\u001b[0m, in \u001b[0;36mHTTPConnectionPool._make_request\u001b[1;34m(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)\u001b[0m\n\u001b[0;32m    492\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m--> 493\u001b[0m     \u001b[43mconn\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m    494\u001b[0m \u001b[43m        \u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    495\u001b[0m \u001b[43m        \u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    496\u001b[0m \u001b[43m        \u001b[49m\u001b[43mbody\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbody\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    497\u001b[0m \u001b[43m        \u001b[49m\u001b[43mheaders\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mheaders\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    498\u001b[0m \u001b[43m        \u001b[49m\u001b[43mchunked\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mchunked\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    499\u001b[0m \u001b[43m        \u001b[49m\u001b[43mpreload_content\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mpreload_content\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    500\u001b[0m \u001b[43m        \u001b[49m\u001b[43mdecode_content\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdecode_content\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    501\u001b[0m \u001b[43m        \u001b[49m\u001b[43menforce_content_length\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43menforce_content_length\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    502\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m    504\u001b[0m \u001b[38;5;66;03m# We are swallowing BrokenPipeError (errno.EPIPE) since the server is\u001b[39;00m\n\u001b[0;32m    505\u001b[0m \u001b[38;5;66;03m# legitimately able to close the connection after sending a valid response.\u001b[39;00m\n\u001b[0;32m    506\u001b[0m \u001b[38;5;66;03m# With this behaviour, the received response is still readable.\u001b[39;00m\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\urllib3\\connection.py:445\u001b[0m, in \u001b[0;36mHTTPConnection.request\u001b[1;34m(self, method, url, body, headers, chunked, preload_content, decode_content, enforce_content_length)\u001b[0m\n\u001b[0;32m    444\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mputheader(header, value)\n\u001b[1;32m--> 445\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mendheaders\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m    447\u001b[0m \u001b[38;5;66;03m# If we're given a body we start sending that in chunks.\u001b[39;00m\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\http\\client.py:1278\u001b[0m, in \u001b[0;36mHTTPConnection.endheaders\u001b[1;34m(self, message_body, encode_chunked)\u001b[0m\n\u001b[0;32m   1277\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m CannotSendHeader()\n\u001b[1;32m-> 1278\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_send_output\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmessage_body\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mencode_chunked\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mencode_chunked\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\http\\client.py:1038\u001b[0m, in \u001b[0;36mHTTPConnection._send_output\u001b[1;34m(self, message_body, encode_chunked)\u001b[0m\n\u001b[0;32m   1037\u001b[0m \u001b[38;5;28;01mdel\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_buffer[:]\n\u001b[1;32m-> 1038\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msend\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmsg\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m   1040\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m message_body \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m   1041\u001b[0m \n\u001b[0;32m   1042\u001b[0m     \u001b[38;5;66;03m# create a consistent interface to message_body\u001b[39;00m\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\http\\client.py:976\u001b[0m, in \u001b[0;36mHTTPConnection.send\u001b[1;34m(self, data)\u001b[0m\n\u001b[0;32m    975\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mauto_open:\n\u001b[1;32m--> 976\u001b[0m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconnect\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m    977\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\urllib3\\connection.py:276\u001b[0m, in \u001b[0;36mHTTPConnection.connect\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m    275\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21mconnect\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m--> 276\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msock \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_new_conn\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m    277\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_tunnel_host:\n\u001b[0;32m    278\u001b[0m         \u001b[38;5;66;03m# If we're tunneling it means we're connected to our proxy.\u001b[39;00m\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\urllib3\\connection.py:207\u001b[0m, in \u001b[0;36mHTTPConnection._new_conn\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m    206\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m SocketTimeout \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m--> 207\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m ConnectTimeoutError(\n\u001b[0;32m    208\u001b[0m         \u001b[38;5;28mself\u001b[39m,\n\u001b[0;32m    209\u001b[0m         \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mConnection to \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mhost\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m timed out. (connect timeout=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtimeout\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m)\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[0;32m    210\u001b[0m     ) \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01me\u001b[39;00m\n\u001b[0;32m    212\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mOSError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n",
      "\u001b[1;31mConnectTimeoutError\u001b[0m: (<urllib3.connection.HTTPConnection object at 0x000002BE183C6C20>, 'Connection to en.wikipedia.org timed out. (connect timeout=None)')",
      "\nThe above exception was the direct cause of the following exception:\n",
      "\u001b[1;31mMaxRetryError\u001b[0m                             Traceback (most recent call last)",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\requests\\adapters.py:667\u001b[0m, in \u001b[0;36mHTTPAdapter.send\u001b[1;34m(self, request, stream, timeout, verify, cert, proxies)\u001b[0m\n\u001b[0;32m    666\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m--> 667\u001b[0m     resp \u001b[38;5;241m=\u001b[39m \u001b[43mconn\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43murlopen\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m    668\u001b[0m \u001b[43m        \u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    669\u001b[0m \u001b[43m        \u001b[49m\u001b[43murl\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    670\u001b[0m \u001b[43m        \u001b[49m\u001b[43mbody\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbody\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    671\u001b[0m \u001b[43m        \u001b[49m\u001b[43mheaders\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mheaders\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    672\u001b[0m \u001b[43m        \u001b[49m\u001b[43mredirect\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[0;32m    673\u001b[0m \u001b[43m        \u001b[49m\u001b[43massert_same_host\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[0;32m    674\u001b[0m \u001b[43m        \u001b[49m\u001b[43mpreload_content\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[0;32m    675\u001b[0m \u001b[43m        \u001b[49m\u001b[43mdecode_content\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[0;32m    676\u001b[0m \u001b[43m        \u001b[49m\u001b[43mretries\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmax_retries\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    677\u001b[0m \u001b[43m        \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtimeout\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    678\u001b[0m \u001b[43m        \u001b[49m\u001b[43mchunked\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mchunked\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    679\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m    681\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m (ProtocolError, \u001b[38;5;167;01mOSError\u001b[39;00m) \u001b[38;5;28;01mas\u001b[39;00m err:\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\urllib3\\connectionpool.py:841\u001b[0m, in \u001b[0;36mHTTPConnectionPool.urlopen\u001b[1;34m(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)\u001b[0m\n\u001b[0;32m    839\u001b[0m     new_e \u001b[38;5;241m=\u001b[39m ProtocolError(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mConnection aborted.\u001b[39m\u001b[38;5;124m\"\u001b[39m, new_e)\n\u001b[1;32m--> 841\u001b[0m retries \u001b[38;5;241m=\u001b[39m \u001b[43mretries\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mincrement\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m    842\u001b[0m \u001b[43m    \u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43merror\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mnew_e\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m_pool\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m_stacktrace\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msys\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mexc_info\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m2\u001b[39;49m\u001b[43m]\u001b[49m\n\u001b[0;32m    843\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m    844\u001b[0m retries\u001b[38;5;241m.\u001b[39msleep()\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\urllib3\\util\\retry.py:519\u001b[0m, in \u001b[0;36mRetry.increment\u001b[1;34m(self, method, url, response, error, _pool, _stacktrace)\u001b[0m\n\u001b[0;32m    518\u001b[0m     reason \u001b[38;5;241m=\u001b[39m error \u001b[38;5;129;01mor\u001b[39;00m ResponseError(cause)\n\u001b[1;32m--> 519\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m MaxRetryError(_pool, url, reason) \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mreason\u001b[39;00m  \u001b[38;5;66;03m# type: ignore[arg-type]\u001b[39;00m\n\u001b[0;32m    521\u001b[0m log\u001b[38;5;241m.\u001b[39mdebug(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mIncremented Retry for (url=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m): \u001b[39m\u001b[38;5;132;01m%r\u001b[39;00m\u001b[38;5;124m\"\u001b[39m, url, new_retry)\n",
      "\u001b[1;31mMaxRetryError\u001b[0m: HTTPConnectionPool(host='en.wikipedia.org', port=80): Max retries exceeded with url: /w/api.php?list=search&srprop=&srlimit=2&limit=2&srsearch=%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B42024%E5%B9%B4%E7%9A%84%E8%90%A5%E4%B8%9A%E6%94%B6%E5%85%A5%E6%98%AF%E5%A4%9A%E5%B0%91%EF%BC%9F%E5%92%8C2023%E5%B9%B4%E7%9B%B8%E6%AF%94%E6%80%8E%E4%B9%88%E6%A0%B7%EF%BC%9F&format=json&action=query (Caused by ConnectTimeoutError(<urllib3.connection.HTTPConnection object at 0x000002BE183C6C20>, 'Connection to en.wikipedia.org timed out. (connect timeout=None)'))",
      "\nDuring handling of the above exception, another exception occurred:\n",
      "\u001b[1;31mConnectTimeout\u001b[0m                            Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[28], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mgraph\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\u001b[43m{\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mquestion\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m阿里巴巴2024年的营业收入是多少？和2023年相比怎么样？\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m}\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m      2\u001b[0m result[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124manswer\u001b[39m\u001b[38;5;124m'\u001b[39m]\u001b[38;5;241m.\u001b[39mcontent\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\langgraph\\pregel\\__init__.py:2739\u001b[0m, in \u001b[0;36mPregel.invoke\u001b[1;34m(self, input, config, stream_mode, output_keys, interrupt_before, interrupt_after, checkpoint_during, debug, **kwargs)\u001b[0m\n\u001b[0;32m   2737\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m   2738\u001b[0m     chunks \u001b[38;5;241m=\u001b[39m []\n\u001b[1;32m-> 2739\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m chunk \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstream(\n\u001b[0;32m   2740\u001b[0m     \u001b[38;5;28minput\u001b[39m,\n\u001b[0;32m   2741\u001b[0m     config,\n\u001b[0;32m   2742\u001b[0m     stream_mode\u001b[38;5;241m=\u001b[39mstream_mode,\n\u001b[0;32m   2743\u001b[0m     output_keys\u001b[38;5;241m=\u001b[39moutput_keys,\n\u001b[0;32m   2744\u001b[0m     interrupt_before\u001b[38;5;241m=\u001b[39minterrupt_before,\n\u001b[0;32m   2745\u001b[0m     interrupt_after\u001b[38;5;241m=\u001b[39minterrupt_after,\n\u001b[0;32m   2746\u001b[0m     checkpoint_during\u001b[38;5;241m=\u001b[39mcheckpoint_during,\n\u001b[0;32m   2747\u001b[0m     debug\u001b[38;5;241m=\u001b[39mdebug,\n\u001b[0;32m   2748\u001b[0m     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs,\n\u001b[0;32m   2749\u001b[0m ):\n\u001b[0;32m   2750\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m stream_mode \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mvalues\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[0;32m   2751\u001b[0m         latest \u001b[38;5;241m=\u001b[39m chunk\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\langgraph\\pregel\\__init__.py:2377\u001b[0m, in \u001b[0;36mPregel.stream\u001b[1;34m(self, input, config, stream_mode, output_keys, interrupt_before, interrupt_after, checkpoint_during, debug, subgraphs)\u001b[0m\n\u001b[0;32m   2371\u001b[0m     \u001b[38;5;66;03m# Similarly to Bulk Synchronous Parallel / Pregel model\u001b[39;00m\n\u001b[0;32m   2372\u001b[0m     \u001b[38;5;66;03m# computation proceeds in steps, while there are channel updates.\u001b[39;00m\n\u001b[0;32m   2373\u001b[0m     \u001b[38;5;66;03m# Channel updates from step N are only visible in step N+1\u001b[39;00m\n\u001b[0;32m   2374\u001b[0m     \u001b[38;5;66;03m# channels are guaranteed to be immutable for the duration of the step,\u001b[39;00m\n\u001b[0;32m   2375\u001b[0m     \u001b[38;5;66;03m# with channel updates applied only at the transition between steps.\u001b[39;00m\n\u001b[0;32m   2376\u001b[0m     \u001b[38;5;28;01mwhile\u001b[39;00m loop\u001b[38;5;241m.\u001b[39mtick(input_keys\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39minput_channels):\n\u001b[1;32m-> 2377\u001b[0m         \u001b[38;5;28;01mfor\u001b[39;00m _ \u001b[38;5;129;01min\u001b[39;00m runner\u001b[38;5;241m.\u001b[39mtick(\n\u001b[0;32m   2378\u001b[0m             loop\u001b[38;5;241m.\u001b[39mtasks\u001b[38;5;241m.\u001b[39mvalues(),\n\u001b[0;32m   2379\u001b[0m             timeout\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstep_timeout,\n\u001b[0;32m   2380\u001b[0m             retry_policy\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mretry_policy,\n\u001b[0;32m   2381\u001b[0m             get_waiter\u001b[38;5;241m=\u001b[39mget_waiter,\n\u001b[0;32m   2382\u001b[0m         ):\n\u001b[0;32m   2383\u001b[0m             \u001b[38;5;66;03m# emit output\u001b[39;00m\n\u001b[0;32m   2384\u001b[0m             \u001b[38;5;28;01myield from\u001b[39;00m output()\n\u001b[0;32m   2385\u001b[0m \u001b[38;5;66;03m# emit output\u001b[39;00m\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\langgraph\\pregel\\runner.py:252\u001b[0m, in \u001b[0;36mPregelRunner.tick\u001b[1;34m(self, tasks, reraise, timeout, retry_policy, get_waiter)\u001b[0m\n\u001b[0;32m    250\u001b[0m \u001b[38;5;66;03m# panic on failure or timeout\u001b[39;00m\n\u001b[0;32m    251\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m--> 252\u001b[0m     \u001b[43m_panic_or_proceed\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m    253\u001b[0m \u001b[43m        \u001b[49m\u001b[43mfutures\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdone\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43munion\u001b[49m\u001b[43m(\u001b[49m\u001b[43mf\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mf\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mt\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mfutures\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mitems\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mt\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01mis\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;129;43;01mnot\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    254\u001b[0m \u001b[43m        \u001b[49m\u001b[43mpanic\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mreraise\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m    255\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m    256\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m exc:\n\u001b[0;32m    257\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m tb \u001b[38;5;241m:=\u001b[39m exc\u001b[38;5;241m.\u001b[39m__traceback__:\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\langgraph\\pregel\\runner.py:504\u001b[0m, in \u001b[0;36m_panic_or_proceed\u001b[1;34m(futs, timeout_exc_cls, panic)\u001b[0m\n\u001b[0;32m    502\u001b[0m                 interrupts\u001b[38;5;241m.\u001b[39mappend(exc)\n\u001b[0;32m    503\u001b[0m             \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m--> 504\u001b[0m                 \u001b[38;5;28;01mraise\u001b[39;00m exc\n\u001b[0;32m    505\u001b[0m \u001b[38;5;66;03m# raise combined interrupts\u001b[39;00m\n\u001b[0;32m    506\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m interrupts:\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\langgraph\\pregel\\executor.py:83\u001b[0m, in \u001b[0;36mBackgroundExecutor.done\u001b[1;34m(self, task)\u001b[0m\n\u001b[0;32m     81\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Remove the task from the tasks dict when it's done.\"\"\"\u001b[39;00m\n\u001b[0;32m     82\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m---> 83\u001b[0m     \u001b[43mtask\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mresult\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m     84\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m GraphBubbleUp:\n\u001b[0;32m     85\u001b[0m     \u001b[38;5;66;03m# This exception is an interruption signal, not an error\u001b[39;00m\n\u001b[0;32m     86\u001b[0m     \u001b[38;5;66;03m# so we don't want to re-raise it on exit\u001b[39;00m\n\u001b[0;32m     87\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtasks\u001b[38;5;241m.\u001b[39mpop(task)\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\concurrent\\futures\\_base.py:451\u001b[0m, in \u001b[0;36mFuture.result\u001b[1;34m(self, timeout)\u001b[0m\n\u001b[0;32m    449\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m CancelledError()\n\u001b[0;32m    450\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_state \u001b[38;5;241m==\u001b[39m FINISHED:\n\u001b[1;32m--> 451\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m__get_result\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m    453\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_condition\u001b[38;5;241m.\u001b[39mwait(timeout)\n\u001b[0;32m    455\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_state \u001b[38;5;129;01min\u001b[39;00m [CANCELLED, CANCELLED_AND_NOTIFIED]:\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\concurrent\\futures\\_base.py:403\u001b[0m, in \u001b[0;36mFuture.__get_result\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m    401\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_exception:\n\u001b[0;32m    402\u001b[0m     \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m--> 403\u001b[0m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_exception\n\u001b[0;32m    404\u001b[0m     \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[0;32m    405\u001b[0m         \u001b[38;5;66;03m# Break a reference cycle with the exception in self._exception\u001b[39;00m\n\u001b[0;32m    406\u001b[0m         \u001b[38;5;28mself\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\concurrent\\futures\\thread.py:58\u001b[0m, in \u001b[0;36m_WorkItem.run\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m     55\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m\n\u001b[0;32m     57\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m---> 58\u001b[0m     result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfn(\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mkwargs)\n\u001b[0;32m     59\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m exc:\n\u001b[0;32m     60\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfuture\u001b[38;5;241m.\u001b[39mset_exception(exc)\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\langgraph\\pregel\\retry.py:39\u001b[0m, in \u001b[0;36mrun_with_retry\u001b[1;34m(task, retry_policy, configurable)\u001b[0m\n\u001b[0;32m     37\u001b[0m     task\u001b[38;5;241m.\u001b[39mwrites\u001b[38;5;241m.\u001b[39mclear()\n\u001b[0;32m     38\u001b[0m     \u001b[38;5;66;03m# run the task\u001b[39;00m\n\u001b[1;32m---> 39\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mtask\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mproc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtask\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minput\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m     40\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m ParentCommand \u001b[38;5;28;01mas\u001b[39;00m exc:\n\u001b[0;32m     41\u001b[0m     ns: \u001b[38;5;28mstr\u001b[39m \u001b[38;5;241m=\u001b[39m config[CONF][CONFIG_KEY_CHECKPOINT_NS]\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\langgraph\\utils\\runnable.py:622\u001b[0m, in \u001b[0;36mRunnableSeq.invoke\u001b[1;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[0;32m    620\u001b[0m     \u001b[38;5;66;03m# run in context\u001b[39;00m\n\u001b[0;32m    621\u001b[0m     \u001b[38;5;28;01mwith\u001b[39;00m set_config_context(config, run) \u001b[38;5;28;01mas\u001b[39;00m context:\n\u001b[1;32m--> 622\u001b[0m         \u001b[38;5;28minput\u001b[39m \u001b[38;5;241m=\u001b[39m context\u001b[38;5;241m.\u001b[39mrun(step\u001b[38;5;241m.\u001b[39minvoke, \u001b[38;5;28minput\u001b[39m, config, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[0;32m    623\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m    624\u001b[0m     \u001b[38;5;28minput\u001b[39m \u001b[38;5;241m=\u001b[39m step\u001b[38;5;241m.\u001b[39minvoke(\u001b[38;5;28minput\u001b[39m, config)\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\langgraph\\utils\\runnable.py:376\u001b[0m, in \u001b[0;36mRunnableCallable.invoke\u001b[1;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[0;32m    374\u001b[0m         run_manager\u001b[38;5;241m.\u001b[39mon_chain_end(ret)\n\u001b[0;32m    375\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m--> 376\u001b[0m     ret \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfunc(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[0;32m    377\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mrecurse \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(ret, Runnable):\n\u001b[0;32m    378\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m ret\u001b[38;5;241m.\u001b[39minvoke(\u001b[38;5;28minput\u001b[39m, config)\n",
      "Cell \u001b[1;32mIn[26], line 30\u001b[0m, in \u001b[0;36msearch_wikipedia\u001b[1;34m(state)\u001b[0m\n\u001b[0;32m     26\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\" 从维基百科检索文档 \"\"\"\u001b[39;00m\n\u001b[0;32m     28\u001b[0m \u001b[38;5;66;03m# 搜索\u001b[39;00m\n\u001b[0;32m     29\u001b[0m search_docs \u001b[38;5;241m=\u001b[39m \u001b[43mWikipediaLoader\u001b[49m\u001b[43m(\u001b[49m\u001b[43mquery\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstate\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mquestion\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[1;32m---> 30\u001b[0m \u001b[43m                              \u001b[49m\u001b[43mload_max_docs\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m2\u001b[39;49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mload\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m     32\u001b[0m  \u001b[38;5;66;03m# 格式化搜索到的信息\u001b[39;00m\n\u001b[0;32m     33\u001b[0m formatted_search_docs \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m---\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;241m.\u001b[39mjoin(\n\u001b[0;32m     34\u001b[0m     [\n\u001b[0;32m     35\u001b[0m         \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m<Document source=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mdoc\u001b[38;5;241m.\u001b[39mmetadata[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msource\u001b[39m\u001b[38;5;124m\"\u001b[39m]\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m page=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mdoc\u001b[38;5;241m.\u001b[39mmetadata\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpage\u001b[39m\u001b[38;5;124m\"\u001b[39m,\u001b[38;5;250m \u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m\"\u001b[39m)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m>\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;132;01m{\u001b[39;00mdoc\u001b[38;5;241m.\u001b[39mpage_content\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m</Document>\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[0;32m     36\u001b[0m         \u001b[38;5;28;01mfor\u001b[39;00m doc \u001b[38;5;129;01min\u001b[39;00m search_docs\n\u001b[0;32m     37\u001b[0m     ]\n\u001b[0;32m     38\u001b[0m )\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\langchain_core\\document_loaders\\base.py:32\u001b[0m, in \u001b[0;36mBaseLoader.load\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m     30\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21mload\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28mlist\u001b[39m[Document]:\n\u001b[0;32m     31\u001b[0m \u001b[38;5;250m    \u001b[39m\u001b[38;5;124;03m\"\"\"Load data into Document objects.\"\"\"\u001b[39;00m\n\u001b[1;32m---> 32\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mlist\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mlazy_load\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\langchain_community\\document_loaders\\wikipedia.py:59\u001b[0m, in \u001b[0;36mWikipediaLoader.lazy_load\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m     46\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[0;32m     47\u001b[0m \u001b[38;5;124;03mLoads the query result from Wikipedia into a list of Documents.\u001b[39;00m\n\u001b[0;32m     48\u001b[0m \n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m     51\u001b[0m \u001b[38;5;124;03m        Wikipedia pages.\u001b[39;00m\n\u001b[0;32m     52\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[0;32m     53\u001b[0m client \u001b[38;5;241m=\u001b[39m WikipediaAPIWrapper(  \u001b[38;5;66;03m# type: ignore[call-arg]\u001b[39;00m\n\u001b[0;32m     54\u001b[0m     lang\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mlang,\n\u001b[0;32m     55\u001b[0m     top_k_results\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mload_max_docs,  \u001b[38;5;66;03m# type: ignore[arg-type]\u001b[39;00m\n\u001b[0;32m     56\u001b[0m     load_all_available_meta\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mload_all_available_meta,  \u001b[38;5;66;03m# type: ignore[arg-type]\u001b[39;00m\n\u001b[0;32m     57\u001b[0m     doc_content_chars_max\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdoc_content_chars_max,  \u001b[38;5;66;03m# type: ignore[arg-type]\u001b[39;00m\n\u001b[0;32m     58\u001b[0m )\n\u001b[1;32m---> 59\u001b[0m \u001b[38;5;28;01myield from\u001b[39;00m \u001b[43mclient\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mload\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mquery\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\langchain_community\\utilities\\wikipedia.py:111\u001b[0m, in \u001b[0;36mWikipediaAPIWrapper.load\u001b[1;34m(self, query)\u001b[0m\n\u001b[0;32m    103\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21mload\u001b[39m(\u001b[38;5;28mself\u001b[39m, query: \u001b[38;5;28mstr\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m List[Document]:\n\u001b[0;32m    104\u001b[0m \u001b[38;5;250m    \u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[0;32m    105\u001b[0m \u001b[38;5;124;03m    Run Wikipedia search and get the article text plus the meta information.\u001b[39;00m\n\u001b[0;32m    106\u001b[0m \u001b[38;5;124;03m    See\u001b[39;00m\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m    109\u001b[0m \n\u001b[0;32m    110\u001b[0m \u001b[38;5;124;03m    \"\"\"\u001b[39;00m\n\u001b[1;32m--> 111\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mlist\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mlazy_load\u001b[49m\u001b[43m(\u001b[49m\u001b[43mquery\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\langchain_community\\utilities\\wikipedia.py:121\u001b[0m, in \u001b[0;36mWikipediaAPIWrapper.lazy_load\u001b[1;34m(self, query)\u001b[0m\n\u001b[0;32m    113\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21mlazy_load\u001b[39m(\u001b[38;5;28mself\u001b[39m, query: \u001b[38;5;28mstr\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Iterator[Document]:\n\u001b[0;32m    114\u001b[0m \u001b[38;5;250m    \u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[0;32m    115\u001b[0m \u001b[38;5;124;03m    Run Wikipedia search and get the article text plus the meta information.\u001b[39;00m\n\u001b[0;32m    116\u001b[0m \u001b[38;5;124;03m    See\u001b[39;00m\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m    119\u001b[0m \n\u001b[0;32m    120\u001b[0m \u001b[38;5;124;03m    \"\"\"\u001b[39;00m\n\u001b[1;32m--> 121\u001b[0m     page_titles \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mwiki_client\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msearch\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m    122\u001b[0m \u001b[43m        \u001b[49m\u001b[43mquery\u001b[49m\u001b[43m[\u001b[49m\u001b[43m:\u001b[49m\u001b[43mWIKIPEDIA_MAX_QUERY_LENGTH\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mresults\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtop_k_results\u001b[49m\n\u001b[0;32m    123\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m    124\u001b[0m     \u001b[38;5;28;01mfor\u001b[39;00m page_title \u001b[38;5;129;01min\u001b[39;00m page_titles[: \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtop_k_results]:\n\u001b[0;32m    125\u001b[0m         \u001b[38;5;28;01mif\u001b[39;00m wiki_page \u001b[38;5;241m:=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_fetch_page(page_title):\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\wikipedia\\util.py:28\u001b[0m, in \u001b[0;36mcache.__call__\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m     26\u001b[0m   ret \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_cache[key]\n\u001b[0;32m     27\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m---> 28\u001b[0m   ret \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_cache[key] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfn(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[0;32m     30\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m ret\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\wikipedia\\wikipedia.py:103\u001b[0m, in \u001b[0;36msearch\u001b[1;34m(query, results, suggestion)\u001b[0m\n\u001b[0;32m    100\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m suggestion:\n\u001b[0;32m    101\u001b[0m   search_params[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msrinfo\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124msuggestion\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m--> 103\u001b[0m raw_results \u001b[38;5;241m=\u001b[39m \u001b[43m_wiki_request\u001b[49m\u001b[43m(\u001b[49m\u001b[43msearch_params\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m    105\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124merror\u001b[39m\u001b[38;5;124m'\u001b[39m \u001b[38;5;129;01min\u001b[39;00m raw_results:\n\u001b[0;32m    106\u001b[0m   \u001b[38;5;28;01mif\u001b[39;00m raw_results[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124merror\u001b[39m\u001b[38;5;124m'\u001b[39m][\u001b[38;5;124m'\u001b[39m\u001b[38;5;124minfo\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;129;01min\u001b[39;00m (\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mHTTP request timed out.\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mPool queue is full\u001b[39m\u001b[38;5;124m'\u001b[39m):\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\wikipedia\\wikipedia.py:737\u001b[0m, in \u001b[0;36m_wiki_request\u001b[1;34m(params)\u001b[0m\n\u001b[0;32m    734\u001b[0m   wait_time \u001b[38;5;241m=\u001b[39m (RATE_LIMIT_LAST_CALL \u001b[38;5;241m+\u001b[39m RATE_LIMIT_MIN_WAIT) \u001b[38;5;241m-\u001b[39m datetime\u001b[38;5;241m.\u001b[39mnow()\n\u001b[0;32m    735\u001b[0m   time\u001b[38;5;241m.\u001b[39msleep(\u001b[38;5;28mint\u001b[39m(wait_time\u001b[38;5;241m.\u001b[39mtotal_seconds()))\n\u001b[1;32m--> 737\u001b[0m r \u001b[38;5;241m=\u001b[39m \u001b[43mrequests\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget\u001b[49m\u001b[43m(\u001b[49m\u001b[43mAPI_URL\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mparams\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mparams\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mheaders\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mheaders\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m    739\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m RATE_LIMIT:\n\u001b[0;32m    740\u001b[0m   RATE_LIMIT_LAST_CALL \u001b[38;5;241m=\u001b[39m datetime\u001b[38;5;241m.\u001b[39mnow()\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\requests\\api.py:73\u001b[0m, in \u001b[0;36mget\u001b[1;34m(url, params, **kwargs)\u001b[0m\n\u001b[0;32m     62\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21mget\u001b[39m(url, params\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[0;32m     63\u001b[0m \u001b[38;5;250m    \u001b[39m\u001b[38;5;124mr\u001b[39m\u001b[38;5;124;03m\"\"\"Sends a GET request.\u001b[39;00m\n\u001b[0;32m     64\u001b[0m \n\u001b[0;32m     65\u001b[0m \u001b[38;5;124;03m    :param url: URL for the new :class:`Request` object.\u001b[39;00m\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m     70\u001b[0m \u001b[38;5;124;03m    :rtype: requests.Response\u001b[39;00m\n\u001b[0;32m     71\u001b[0m \u001b[38;5;124;03m    \"\"\"\u001b[39;00m\n\u001b[1;32m---> 73\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m request(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mget\u001b[39m\u001b[38;5;124m\"\u001b[39m, url, params\u001b[38;5;241m=\u001b[39mparams, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\requests\\api.py:59\u001b[0m, in \u001b[0;36mrequest\u001b[1;34m(method, url, **kwargs)\u001b[0m\n\u001b[0;32m     55\u001b[0m \u001b[38;5;66;03m# By using the 'with' statement we are sure the session is closed, thus we\u001b[39;00m\n\u001b[0;32m     56\u001b[0m \u001b[38;5;66;03m# avoid leaving sockets open which can trigger a ResourceWarning in some\u001b[39;00m\n\u001b[0;32m     57\u001b[0m \u001b[38;5;66;03m# cases, and look like a memory leak in others.\u001b[39;00m\n\u001b[0;32m     58\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m sessions\u001b[38;5;241m.\u001b[39mSession() \u001b[38;5;28;01mas\u001b[39;00m session:\n\u001b[1;32m---> 59\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m session\u001b[38;5;241m.\u001b[39mrequest(method\u001b[38;5;241m=\u001b[39mmethod, url\u001b[38;5;241m=\u001b[39murl, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\requests\\sessions.py:589\u001b[0m, in \u001b[0;36mSession.request\u001b[1;34m(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)\u001b[0m\n\u001b[0;32m    584\u001b[0m send_kwargs \u001b[38;5;241m=\u001b[39m {\n\u001b[0;32m    585\u001b[0m     \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtimeout\u001b[39m\u001b[38;5;124m\"\u001b[39m: timeout,\n\u001b[0;32m    586\u001b[0m     \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mallow_redirects\u001b[39m\u001b[38;5;124m\"\u001b[39m: allow_redirects,\n\u001b[0;32m    587\u001b[0m }\n\u001b[0;32m    588\u001b[0m send_kwargs\u001b[38;5;241m.\u001b[39mupdate(settings)\n\u001b[1;32m--> 589\u001b[0m resp \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msend(prep, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39msend_kwargs)\n\u001b[0;32m    591\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m resp\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\requests\\sessions.py:703\u001b[0m, in \u001b[0;36mSession.send\u001b[1;34m(self, request, **kwargs)\u001b[0m\n\u001b[0;32m    700\u001b[0m start \u001b[38;5;241m=\u001b[39m preferred_clock()\n\u001b[0;32m    702\u001b[0m \u001b[38;5;66;03m# Send the request\u001b[39;00m\n\u001b[1;32m--> 703\u001b[0m r \u001b[38;5;241m=\u001b[39m adapter\u001b[38;5;241m.\u001b[39msend(request, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[0;32m    705\u001b[0m \u001b[38;5;66;03m# Total elapsed time of the request (approximately)\u001b[39;00m\n\u001b[0;32m    706\u001b[0m elapsed \u001b[38;5;241m=\u001b[39m preferred_clock() \u001b[38;5;241m-\u001b[39m start\n",
      "File \u001b[1;32mD:\\CacheData\\anaconda\\envs\\python310\\lib\\site-packages\\requests\\adapters.py:688\u001b[0m, in \u001b[0;36mHTTPAdapter.send\u001b[1;34m(self, request, stream, timeout, verify, cert, proxies)\u001b[0m\n\u001b[0;32m    685\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(e\u001b[38;5;241m.\u001b[39mreason, ConnectTimeoutError):\n\u001b[0;32m    686\u001b[0m     \u001b[38;5;66;03m# TODO: Remove this in 3.0.0: see #2811\u001b[39;00m\n\u001b[0;32m    687\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(e\u001b[38;5;241m.\u001b[39mreason, NewConnectionError):\n\u001b[1;32m--> 688\u001b[0m         \u001b[38;5;28;01mraise\u001b[39;00m ConnectTimeout(e, request\u001b[38;5;241m=\u001b[39mrequest)\n\u001b[0;32m    690\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(e\u001b[38;5;241m.\u001b[39mreason, ResponseError):\n\u001b[0;32m    691\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m RetryError(e, request\u001b[38;5;241m=\u001b[39mrequest)\n",
      "\u001b[1;31mConnectTimeout\u001b[0m: HTTPConnectionPool(host='en.wikipedia.org', port=80): Max retries exceeded with url: /w/api.php?list=search&srprop=&srlimit=2&limit=2&srsearch=%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B42024%E5%B9%B4%E7%9A%84%E8%90%A5%E4%B8%9A%E6%94%B6%E5%85%A5%E6%98%AF%E5%A4%9A%E5%B0%91%EF%BC%9F%E5%92%8C2023%E5%B9%B4%E7%9B%B8%E6%AF%94%E6%80%8E%E4%B9%88%E6%A0%B7%EF%BC%9F&format=json&action=query (Caused by ConnectTimeoutError(<urllib3.connection.HTTPConnection object at 0x000002BE183C6C20>, 'Connection to en.wikipedia.org timed out. (connect timeout=None)'))"
     ]
    }
   ],
   "source": [
    "result = graph.invoke({\"question\": \"阿里巴巴2024年的营业收入是多少？和2023年相比怎么样？\"})\n",
    "result['answer'].content"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "06771939",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3.10",
   "language": "python",
   "name": "python310"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.16"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
